#pragma once
#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>
#include <memory>
#include <functional>
#include "socket.hpp"
#include "inetaddr.hpp"
class Request
{
public:
    Request() {}
    Request(int x, int y, char oper) : _x(x), _y(y), _oper(oper) {}
    std::string Sequence()
    {
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["oper"] = _oper;
        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
        std::stringstream ss;
        sw->write(root, &ss);
        return ss.str();
    }
    void Rsequence(std::string &massage)
    {
        Json::Value root;
        Json::Reader reader;
        reader.parse(massage, root);
        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();
    }
    int GetX() { return _x; }
    int GetY() { return _y; }
    char GetOper() { return _oper; }

private:
    int _x;
    int _y;
    char _oper;
};

class Responce
{
public:
    Responce() {}
    Responce(int result, int code) : _result(result), _code(code) {}
    std::string Sequence()
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;
        Json::StreamWriterBuilder swb;
        std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
        std::stringstream ss;
        sw->write(root, &ss);
        return ss.str();
    }
    void Rsequence(std::string &massage)
    {
        Json::Value root;
        Json::Reader reader;
        reader.parse(massage, root);
        _result = root["result"].asInt();
        _code = root["code"].asInt();
    }
    void SetResult(int result) { _result = result; }
    void SetCode(int code) { _code = code; }
    void Show()
    {
        std::cout << "result : " << _result << "[ " << _code << " ]" << std::endl;
    }

private:
    int _result; // 结果
    int _code;   // 标识计算是否出错
};

using task_t = std::function<Responce(Request &req)>;
const std::string sep = "\r\n";
class Protocol
{
public:
    Protocol() {}
    Protocol(task_t task) : _task(task) {}
    std::string Encode(const std::string &str)
    {
        int str_len = str.size();
        return std::to_string(str_len) + sep + str + sep;
    }
    bool Decode(std::string &massage, std::string *ComPacket)
    {
        auto pos = massage.find(sep);
        if (pos == std::string::npos)
            return false;
        std::string head = massage.substr(0, pos);
        int len = std::stoi(head.c_str());        // 有效载荷长度
        int sep_len = sep.size();                 // 特殊标识长度
        int packet_len = pos + len + sep_len * 2; // 完整报文长度
        if (massage.size() < packet_len)
            return false;
        *ComPacket = massage.substr(pos + sep_len, len); // 提取完整报文
        std::cout << "------ComPacket------\n"
                  << *ComPacket << std::endl;
        massage.erase(0, packet_len); // 在信息中删除该完整报文
        std::cout << "------massage------\n"
                  << massage << std::endl;
        return true;
    }
    void GetRequest(std::shared_ptr<Socket> fd, InetAddr &peer)
    {
        std::string buff; // 读取缓冲区
        while (true)
        {
            std::string packet; // 完整报文
            int n = fd->Recv(buff);
            if (n > 0)
            {
                std::cout << "------buff------\n"
                          << buff << std::endl;
                // 1. 判断报文的完整性
                while (Decode(buff, &packet))
                {
                    std::cout << "------buff------\n"
                              << buff << std::endl;
                    std::cout << "------packet------\n"
                              << packet << std::endl;
                    // 存在完整报文
                    Request req;
                    // 2. 反序列化
                    req.Rsequence(packet);
                    // 3. 处理业务
                    // ... 由上层提供
                    Responce res = _task(req);
                    // 4. 将结果序列化
                    std::string json_res = res.Sequence();
                    std::cout << "------json_res------\n"
                              << json_res << std::endl;
                    // 5. 加协议报头
                    std::string send_res = Encode(json_res);
                    std::cout << "------send_res------\n"
                              << send_res << std::endl;
                    // 6. 将信息发送回去
                    fd->Send(send_res);
                }
            }
            else if (n == 0)
            {
                LOG(Level::INFO) << "client exit";
                exit(0);
            }
            else
            {
                LOG(Level::FATAL) << "recv error";
                exit(1);
            }
            // 不存在完整报文就继续读取
        }
    }
    std::string BuildComData(int x, int y, char oper)
    {
        Request res(x, y, oper);
        std::string json_res = res.Sequence();
        return Encode(json_res);
    }
    bool GetResponce(std::shared_ptr<Socket> fd, std::string &buff, Responce *res)
    {
        // 读取
        int n = fd->Recv(buff);
        if (n > 0)
        {
            std::string packet;
            if (Decode(buff, &packet))
            {
                // 反序列化
                res->Rsequence(packet);
                return true;
            }
            return false;
        }
        else if (n == 0)
        {
            LOG(Level::INFO) << "opponent exit";
            exit(0);
        }
        else
        {
            LOG(Level::FATAL) << "recv error";
            exit(1);
        }
    }

private:
    task_t _task;
};